/*
 * Low level disk I/O module
 */
#include "lib_fs_disk_io.h"
#include <stdio.h>


#define lib_fs_disk_io_filename    "disk.bin"
private boolean_t lib_fs_disk_io_is_verbose;
#define sector_size                lib_fs_list_block_size /* 128, 256, 512 ... bytes */
private FILE      * p_my_disk;
private uint32_t  disk_sector_last_rd;
private uint32_t  disk_sector_last_wr;
//private uint8_t   disk_sector[sector_size];

/* -------------------------------------------------------------------------------------------------------------- */
/*
 * Command code for disk_ioctrl fucntion
 */

/* Generic command (mandatory for FatFs) */
#define CTRL_SYNC           0           /* Flush disk cache (for write functions) */
#define GET_SECTOR_COUNT    1           /* Get media size (for only f_mkfs()) */
#define GET_SECTOR_SIZE     2           /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
#define GET_BLOCK_SIZE      3           /* Get erase block size (for only f_mkfs()) */
/* -------------------------------------------------------------------------------------------------------------- */



private void buffer_init
(
    uint8_t buffer[],
    uint32_t value
)
{
    uint32_t i;
    for (i = 0; i < sector_size; i++)
    {
        buffer[i] = value;
    }
}


boolean_t disk_init
(
    uint8_t diskID                  /* Physical drive nmuber (0..) */
)
{
    boolean_t disk_status;

    if (lib_fs_disk_io_is_verbose == True)
    {
        printf("disk_init, sector_size=%u\n", sector_size);
    }


    lib_fs_disk_io_is_verbose == True;

    if (lib_fs_disk_io_is_verbose == True)
    {
        printf("opening %s ... ", lib_fs_disk_io_filename);
        printf("done\n");
    }

    p_my_disk = fopen(lib_fs_disk_io_filename, "r+");
    if (p_my_disk != NULL)
    {
        disk_status = True;
    }
    else
    {
        printf("disk_init has a failure\n");
        disk_status = False;
    }

    disk_sector_last_rd = 0;
    disk_sector_last_wr = 0;

    return disk_status;
}


void disk_verbose(boolean_t is_verbose)
{
    lib_fs_disk_io_is_verbose = is_verbose;
}

boolean_t disk_done
(
    uint8_t diskID                  /* Physical drive nmuber (0..) */
)
{
    boolean_t ans;

    if (p_my_disk != NULL)
    {
        fclose(p_my_disk);
        ans = True;
    }
    else
    {
        ans = False;
    }

    return ans;
}

disk_ans_t disk_ioctl
(
    uint8_t diskID,                /* Physical drive nmuber (0..) */
    uint8_t cmd,                   /* Control code */
    uint8_t buffer[]               /* Buffer to send/receive control data */
)
{
    disk_ans_t ans;

    ans = RES_PARERR;
    ans = RES_OK;
    return ans;
}

boolean_t disk_status
(
    uint8_t diskID                   /* Physical drive nmuber (0..) */
)
{
    boolean_t ans;

    ans = True;
    return ans;
}

disk_ans_t disk_read
(
    uint8_t diskID,                /* Physical drive nmuber (0..) */
    uint8_t buffer[],              /* Data buffer to store read data */
    uint16_t sector,               /* Sector address (LBA) */
    uint8_t count                  /* Number of sectors to read (1..128) */
)
{
    uint32_t   addr;
    disk_ans_t ans;

    addr  = (sector * sector_size);
    count = 1;

    if (sector == 0)
    {
        printf("### disk_read @ sector0\n");
    }

    //if ((sector==disk_sector_last_rd) logicalAnd (disk_sector_last_wr!=disk_sector_last_rd))
    if (0)
    {
        /*
         * skip
         */
        if (lib_fs_disk_io_is_verbose == True)
        {
            printf("skipping reading sect=%lx, addr=%lx, count=%lu\n", (uint32_t) sector, (uint32_t) addr, (uint32_t) count);
        }
    }
    else
    {
        disk_sector_last_rd = sector;

        fseek(p_my_disk, addr, SEEK_SET);
        if (lib_fs_disk_io_is_verbose == True)
        {
            printf("reading sect=%lx, addr=%lx, count=%lu\n", (uint32_t) sector, (uint32_t) addr, (uint32_t) count);
        }
        fread(buffer, sector_size, count, p_my_disk);
    }
    ans = RES_OK;

    return ans;
}


disk_ans_t disk_write
(
    uint8_t diskID,                /* Physical drive nmuber (0..) */
    uint8_t buffer[],              /* Data to be written */
    uint16_t sector,               /* Sector address (LBA) */
    uint8_t count                  /* Number of sectors to write (1..128) */
)
{
    uint32_t   addr;
    disk_ans_t ans;

    addr  = (sector * sector_size);
    count = 1;

    if (sector == 0)
    {
        printf("### disk_write @ sector0\n");
    }

    //if ((sector==disk_sector_last_wr) logicalAnd (disk_sector_last_wr!=disk_sector_last_rd))
    if (0)
    {
        /*
         * skip
         */
        if (lib_fs_disk_io_is_verbose == True)
        {
            printf("skipping writing sect=%lx, addr=%lx, count=%lu\n", (uint32_t) sector, (uint32_t) addr, (uint32_t) count);
        }
    }
    else
    {
        disk_sector_last_wr = sector;

        fseek(p_my_disk, addr, SEEK_SET);
        if (lib_fs_disk_io_is_verbose == True)
        {
            printf("writing sect=%lx, addr=%lx, count=%lu\n", (uint32_t) sector, (uint32_t) addr, (uint32_t) count);
        }
        fwrite(buffer, sector_size, 1, p_my_disk);
    }

    ans = RES_PARERR;
    ans = RES_OK;

    ans;
}

